﻿Imports System.Reflection
Imports Microsoft.Xna.Framework
Imports Runa.UI.Input
Imports Runa.Core.Services
Imports Runa.Foundation.Messaging
Imports Runa.Scripting.ScriptingHost
Imports Runa.UI.Effects
Imports Runa.Graphics.Effects
Imports System.IO
Imports Runa.Common.Helper
Imports Runa.Foundation.Diagnostics

Partial Public Class GameRender
    Implements IEventsMappingService

#Region "This is for the storage of global status such as game progress."
    Public Property GlobalStatus() As New Dictionary(Of String, Object)
#End Region

#Region "This is the container of high-level game components."
    Public ReadOnly Property Game() As Game
        Get
            Return Me
        End Get
    End Property

    Public ReadOnly Property Graphics() As GraphicsDeviceManager Implements IGameParameterService.Graphics
        Get
            Return Me.m_graphics
        End Get
    End Property

    Public Property RootFrame() As Runa.UI.Compoents.Frame
    Public Property InputManager() As InputManager
    Public Property MessageHandlers() As New Dictionary(Of String, MessageType) Implements IEventsMappingService.MessageHandlers
#End Region

#Region "APIs for setting and reading global variants."
    Public Sub LoadAllTexutres()
        Dim lst = Helper.g_fileStorage.GetFiles(Me.GameContentRoot & "\Images")
        For Each t In lst.Where(Function(item) item.ToLower().EndsWith(".xnb"))
            t = "Images\" & t
            Me.Textures.Add(Path.GetFileNameWithoutExtension(t), Me.m_contentManager.LoadTexture2D(t))
        Next
    End Sub

    Public Sub LoadAllFonts()
        Dim lst = Helper.g_fileStorage.GetFiles(Me.GameContentRoot & "\Fonts")
        For Each t In lst.Where(Function(item) item.ToLower().EndsWith(".xnb"))
            t = "Fonts\" & t
            Me.Fonts.Add(Path.GetFileNameWithoutExtension(t), Me.m_contentManager.LoadSpriteFont(t))
        Next
    End Sub

    Public Sub LoadAllAudios()
        Dim lst = Helper.g_fileStorage.GetFiles(Me.GameContentRoot & "\Audios")
        For Each t In lst.Where(Function(item) item.ToLower().EndsWith(".xnb"))
            t = "Audios\" & t
            Me.Audios.Add(Path.GetFileNameWithoutExtension(t), Me.m_contentManager.LoadAudio(t))
        Next
    End Sub

    Public Sub LoadAllPages()
        Try
            Dim lst = Helper.g_fileStorage.GetFiles(Me.GameContentRoot & "\Pages").Where(Function(item) item.ToLower().EndsWith(".rb"))
            Dim runtimeHandler = New EventHandler(Of RuntimeErrorEventArgs)(AddressOf Me.ScriptTask_OnRuntimeError)
            Dim compileHandler = New EventHandler(Of CompilationErrorEventArgs)(AddressOf Me.ScriptTask_OnCompilationFailed)
            For Each p In lst
                Dim fn = Path.GetFileNameWithoutExtension(p)
                p = Combine(Me.GameContentRoot, "Pages", p)
                Me.Pages.Add(fn,
                    Runa.UI.Controls.Page.LoadFromGameDirectory(Me.RootFrame,
                        p, Me.m_physicalStorage, runtimeHandler, compileHandler))
            Next
        Catch ex As Exception
            Me.GameTracer.TraceMessage(ex.Message & ex.StackTrace.ToString())
        End Try
    End Sub

    Public Sub LoadAllEffect(Optional ByVal isGPUEnabled As Boolean = False)
        Dim typs = GetType(WpfEffectBase).Assembly.ExportedTypes()
        Dim ets = (From item In typs Where item.Name.EndsWith("Effect") Select item).ToList()
        ets.ForEach(
            Sub(item)
                Dim e = CType(Activator.CreateInstance(item, New Object() {Me}), EffectBase)
                Me.Effects.Add(item.Name, e)
            End Sub)
        Dim lst = Helper.g_fileStorage.GetFiles(Me.GameContentRoot & "\Effects")
        For Each t In lst.Where(Function(item) item.ToLower().EndsWith(".xnb"))
            t = "Effects\" & t
            Me.Effects.Add(Path.GetFileNameWithoutExtension(t), New EffectBase(Me, Me.m_contentManager.Load(Of Effect)(t)))
        Next
    End Sub

    Public Function LoadScript(ByVal relativePath As String) As List(Of String)
        Dim lst As New List(Of String)
        Dim text = Me.m_contentManager.LoadAllText(relativePath)
        Dim lines = text.Split(New String() {vbCrLf}, StringSplitOptions.RemoveEmptyEntries)
        For Each line In lines
            line = line.Trim()
            If line.StartsWith("#") = False And line.Trim() <> "" Then
                lst.Add(line)
            End If
        Next
        Return lst
    End Function

    Public Function LoadScriptDictionary(ByVal relativePath As String) As Dictionary(Of String, String)
        Dim dic As New Dictionary(Of String, String)
        Dim text = Me.m_contentManager.LoadAllText(relativePath)
        Dim lines = text.Split(New String() {vbCrLf}, StringSplitOptions.RemoveEmptyEntries)
        For Each line In lines
            Dim items = line.Split(","c)
            If items.Length >= 2 Then
                Dim value = items.Last()
                For Each key In items.Take(items.Length - 1)
                    If dic.ContainsKey(key) = False Then
                        dic.Add(key, value)
                    Else
                        Me.GameTracer.TraceMessage("Duplicated key {0} found.", key)
                    End If
                Next
                If dic.ContainsKey(value) = False Then
                    dic.Add(value, value)
                Else
                    Me.GameTracer.TraceMessage("Duplicated key {0} found.", value)
                End If
            End If
        Next
        Return dic
    End Function

    Public Sub GlobalSetResource(ByVal resourceName As String, ByVal globalName As String)
        Try
            If Me.Textures.ContainsKey(resourceName) Then
                If Me.GlobalStatus.ContainsKey(globalName) Then
                    Me.GlobalStatus(globalName) = Me.Textures(resourceName)
                Else
                    Me.GlobalStatus.Add(globalName, Me.Textures(resourceName))
                End If
            ElseIf Me.Fonts.ContainsKey(resourceName) Then
                If Me.GlobalStatus.ContainsKey(globalName) Then
                    Me.GlobalStatus(globalName) = Me.Fonts(resourceName)
                Else
                    Me.GlobalStatus.Add(globalName, Me.Fonts(resourceName))
                End If
            ElseIf Me.Audios.ContainsKey(resourceName) Then
                If Me.GlobalStatus.ContainsKey(globalName) Then
                    Me.GlobalStatus(globalName) = Me.Audios(resourceName)
                Else
                    Me.GlobalStatus.Add(globalName, Me.Audios(resourceName))
                End If
            Else
                Throw New ArgumentOutOfRangeException("The given key is not found in the loaded resources.")
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Sub GlobalSetValue(ByVal globalName As String, ByVal obj As Object)
        Try
            If Me.GlobalStatus.ContainsKey(globalName) Then
                Me.GlobalStatus(globalName) = obj
            Else
                Me.GlobalStatus.Add(globalName, obj)
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Sub GlobalSetObject(Of T)(ByVal globalName As String, ByVal obj As T)
        Try
            If Me.GlobalStatus.ContainsKey(globalName) Then
                Me.GlobalStatus(globalName) = obj
            Else
                Me.GlobalStatus.Add(globalName, obj)
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Function GlobalGet(Of T)(ByVal vn As String) As T
        Try
            If Me.GlobalStatus.ContainsKey(vn) Then
                Return CType(Me.GlobalStatus(vn), T)
            Else
                Me.GlobalStatus.Add(vn, Nothing)
                Return Nothing
            End If
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Public Sub GlobalSave()
        Using ms = Me.m_Serializer.Serialize(Me.GlobalStatus)
            'My.Computer.FileSystem.WriteAllBytes(Me.m_contentManager.PhysicalStorage.PhysicalPath & "\" & Me.SaveDataFileName, ms.ToArray(), False)
            Using fs = Me.m_contentManager.PhysicalStorage.OpenFile(Me.SaveDataFileName, FileMode.OpenOrCreate)
                Dim data = ms.ToArray()
                fs.Write(data, 0, data.Length)
                fs.Flush()
                fs.Close()
            End Using
        End Using
    End Sub
#End Region

End Class